2. 애플리케이션 계층

@VERO
Created Date · 2023년 11월 27일 11:11
Last Updated Date · 2024년 04월 23일 06:04

네트워크 애플리케이션의 원리

네트워크 애플리케이션 개발의 중심은 다른 위치의 종단 시스템에서 동작하고 네트워크를 통해 서로 통신하는 프로그램을 작성하는 것이다.

여러분이 새로운 애플리케이션을 개발할 때는 여러 종단 시스템에서 실행되는 소프트웨어를 작성해야 한다. 중요한 것은 우리가 라우터나 링크 계층 스위치처럼 네트워크 코어 장비에서 실행되는 소프트웨어까지 작성할 필요는 없다는 점이다.

이와 같이 종단 시스템에만 애플리케이션 소프트웨어가 존재한다는 기본 설계 방식은 인터넷 애플리케이션들이 빠르고 널리 발전하는 원동력이 되었다.

네트워크 애플리케이션 구조

애플리케이션 구조는 네트워크 구조와 분명히 다르다. 애플리케이션 구조는 애플리케이션 개발자가 설계하며, 또한 애플리케이션이 다양한 종단 시스템에서 어떻게 조직되어야 하는지를 알려준다. 애플리케이션 구조를 선택할 때 애플리케이션 개발자는 현대 네트워크 애플리케이션에서 사용되는 두 가지 잘 알려진 구조 중 하나로 선택할 수 있다.

클라이언트-서버 구조에서 항상 동작하고 있는 호스트를 서버라고 부르는데, 서버와의 서비스는 클라이언트라는 다른 호스트들로부터 서비스 요청을 보낸다 . 클라이언트-서버 구조에서 클라이언트는 서로 직접적으로 통신하지 않는다. 또한 클라이언트-서버 구조에서는 서버가 고정 IP 주소라는 잘 알려진 주소를 갖는다는 것이다. 서버는 항상 동작하고 있으므로 클라이언트는 서버 주소로 패킷을 보내서 언제든지 서버에 연결할 수 있다.

때로는 클라이언트-서버 애플리케이션에서 하나의 서버 호스트가 자신의 클라이언트로부터 오는 모든 요청에 다 응답하는 것은 불가능하다. 이러한 이유로 많은 수의 호스트를 갖춘 데이터 센터가 강력한 가상의 서버를 생성하는 역할로 사용된다.

P2P 구조에서는 항상 켜져 있는 인프라스트럭처 서버에 최소로 의존하거나 전혀 의존하지 않는다. 대신에 애플리케이션은 피어라는 간헐적으로 연결된 호스트 쌍이 서로 직접 통신하게 한다. 피어는 서비스 제공자가 소유하지 않고, 사용자들이 제어하는 데스크탑과 랩탑이다.
특정 서버를 통하지 않고 피어가 통신하므로, 해당 구조를 peer-to-peer 라고 한다.
P2P 구조는 자가 확장성이라는 특성을 갖는다. 또한 P2P 구조는 일반적으로 상당한 서버 인프라스트럭처와 서버 대역폭을 요구하지 않기 때문에 비용 효율적이다.
그러나 고도의 분산 구조 특성으로 인해 보안, 성능, 신뢰성 면에서 도전을 맞이하고 있다.

프로세스 간 통신

운영체제 용어에서 실제 통신하는 것은 프로그램이 아니라 프로세스다. 프로세스는 종단 시스템에서 실행되는 프로그램이다.
통신 프로세스가 같은 종단 시스템에서 실행될 때 그들은 서로 프로세스 간에 통신한다.

2개의 종단 시스템에서 프로세스는 컴퓨터 네트워크를 통한 메시지 교환으로 서로 통신한다.
송신 프로세스는 메시지를 만들어서 네트워크로 보낸다. 수신 프로세스는 메시지를 받고 역으로 메시지를 보냄으로써 응답한다.

클라이언트와 서버 프로세스

네트워크 애플리케이션은 네트워크에서 서로 메시지를 보내는 두 프로세스로 구성된다.
통신하는 프로세스 각 쌍에 대해 일반적으로 클라이언트의 프로세스와 서버의 프로세스 중 하나로 이름을 짓는다.

두 프로세스 간의 통신 세션에서 통신을 초기화(다른 프로세스와 세션을 시작하려고 접속을 초기화)하는 프로세스를 클라이언트라고 하고, 세션을 시작하기 위해 접속을 기다리는 프로세스를 서버라고 한다.

프로세스와 컴퓨터 네트워크 사이의 인터페이스

대부분의 애플리케이션은 두 프로세스가 메시지를 서로에게 보내는 통신 프로세스 쌍으로 구성된다.
하나의 프로세스로부터 다른 프로세스로 보내는 메시지는 네트워크를 통해 움직인다.

프로세스는 소켓을 통해 네트워크로 메시지를 보내고 받는다.
소켓은 호스트의 애플리케이션 계층과 트랜스포트 계층 간의 인터페이스다.
또한 소켓은 네트워크 애플리케이션이 인터넷에 만든 프로그래밍 인터페이스이므로, 애플리케이션과 네트워크 사이의 API 라고도 한다.

애플리케이션은 소켓의 애플리케이션 계층에 대한 모든 통제권을 갖지만, 소켓의 트랜스포트 계층에 대한 통제권은 거의 갖지 못한다.
트랜스포트 계층에 대한 애플리케이션 개발자의 통제는 (1) 트랜스포트 프로토콜의 선택, (2) 최대 버퍼와 최대 세그먼트 크기 같은 약간의 트랜스포트 계층 매개변수의 설정뿐이다.

프로세스 주소 배정

한 호스트상에서 수행되고 있는 프로세스가 패킷을 다른 호스트에서 수행되고 있는 프로세스로 패킷을 보내기 위해서는 수신 프로세스가 주소를 갖고 있을 필요가 있다.

수신 프로세스를 식별하기 위해서는 다음과 같은 두 가지 정보가 명시되어야 한다.

  1. 호스트의 주소
  2. 목적지 호스트 내의 수신 프로세스를 명시하는 식별자

인터넷에서 호스트는 IP 주소로 식별된다. IP 주소는 32비트로 구성되며, 호스트를 유일하게 식별한다.
메시지가 전달되어야 하는 호스트의 주소를 아는 것과 더불어 송신 호스트는 수신 호스트에서 수행되고 있는 수신 프로세스도 식별해야 한다. 목적지 포트 번호는 일반적으로 한 호스트가 많은 네트워크 애플리케이션을 수행할 수 있기 때문에 사용된다.

애플리케이션이 이용 가능한 트랜스포트 서비스

송신 측의 애플리케이션은 소켓을 통해 메시지를 보낸다. 소켓의 반대편에서 트랜스포트 프로토콜은 네트워크를 통해 그 메시지를 수신 프로세스의 소켓으로 이동시킬 책임이 있다.

인터넷을 포함해서 많은 네트워크는 하나 이상의 트랜스포트 프로토콜을 제공한다. 애플리케이션을 개발할 때는 사용 가능한 트랜스포트 프로토콜 중에서 하나를 선택해야 한다.

트랜스포트 계층 프로토콜은 넓은 범위에서 신뢰적 데이터 전송, 처리율, 시간, 보안이라는 네 가지 차원의 서비스를 제공할 수 있다.

신뢰적 데이터 전송

전자메일, 파일 전송, 원격 호스트 접속, 재무 애플리케이션 같은 애플리케이션의 경우 데이터의 손실이 위험한 결과를 초래할 수 있다. 이를 위해 트랜스포트 계층 프로토콜은 프로세스 간 신뢰적 데이터 전송 서비스를 제공할 수 있다.
트랜스포트 프로토콜이 이 서비스를 제공할 때, 송신 프로세스는 데이터를 소켓으로 보내고, 그 데이터가 오류 없이 수신 프로세스에 도착할 것이라는 확신을 갖는다.

트랜스포트 계층 프로토콜이 신뢰적 데이터 전송을 제공하지 않을 때, 송신 프로세스가 보낸 데이터는 수신 프로세스에 전혀 도착하지 않을 수 있다. 이는 손실 허용 애플리케이션의 경우, 즉, 어느 정도의 데이터 손실을 참아낼 수 있는 실시간 오디오/비디오 혹은 저장 오디오/비디오 같은 멀티미디어 애플리케이션에서는 받아들여질 수 있다.

처리율

처리율은 네트워크 경로를 따라 두 프로세스 간의 통신 세션에서 송신 프로세스가 수신 프로세스로 비트를 전달할 수 있는 비율을 나타낸다.
다른 세션들이 네트워크 경로를 따라 대역폭을 공유하고, 이 세션들이 생겼다 없어졌다 하기 떄문에 가용한 처리율은 시간에 따라 변동한다.

애플리케이션은 r비트/초 의 보장된 처리율을 요구할 수 있고, 트랜스포트 프로토콜은 가용한 처리율이 항상 적어도 r bps 임을 보장한다.

처리율 요구 사항을 갖는 애플리케이션은 대역폭 민감 애플리케이션이라고 한다. 반면 탄력적 애플리케이션은 가용한 처리율을 많으면 많은 대로 적으면 적은 대로 이용할 수 있다. 전자메일, 파일 전송, 웹 전송이 융통성 있는 애플리케이션이다.

시간

트랜스포트 계층 프로토콜은 시간 보장을 제공할 수 있다.
인터넷 전화, 가상 환경, 원격회의, 다자간 게임과 같은 실시간 상호작용 애플리케이션이 효과적으로 동작하기 위해서는 데이터 전송에 엄격한 시간 제한 조건이 요구된다.

비실시간 애플리케이션의 경우 낮은 지연이 항상 높은 지연보다 선호되지만 종단 간 지연에 엄격한 제약을 받는 것은 아니다.

보안

트랜스포트 프로토콜은 애플리케이션에 하나 이상의 보안 서비스를 제공할 수 있다.

송신 호스트에서 트랜스포트 프로토콜은 송신 프로세스가 전송하는 모든 데이터를 암호화할 수 있고, 수신 호스트에서 트랜스포트 프로토콜은 그 데이터를 수신 프로세스로 전달하기 전에 데이터의 암호를 해독할 수 있다.
이러한 서비스는 데이터가 송신과 수신 프로세스 사이에서 어느 정도 관찰된다 하더라도 두 프로세스 사이에 기밀성을 제공한다. 그 외에도 데이터 무결성과 종단 인증 등을 포함할 수 있다.

인터넷 전송 프로토콜이 제공하는 서비스

인터넷은 애플리케이션에게 2개의 전송 프로토콜, 즉 UDP (User Datagram Protocol) 와 TCP (Transmission Control Protocol) 을 제공한다.

TCP 서비스

TCP 서비스 모델은 연결지향형 서비스와 신뢰적인 데이터 전송 서비스를 포함한다.

  • 연결지향형 서비스: 애플리케이션 계층 메시지를 전송하기 전에 TCP는 클라이언트와 서버가 서로 전송 제어 정보를 교환하게 한다. 이러한 핸드셰이킹 과정이 클라이언트와 서버에 패킷이 곧 도달할테니 준비하라고 알리는 역할을 한다. 핸드셰이킹 단계 후, TCP 연결이 두 프로세스의 소켓 사이에 존재한다고 말한다. 이 연결은 두 프로세스가 서로에게 동시에 메시지를 보낼 수 있기에 전이중 (full-duplex) 연결이라고 한다. 애플리케이션이 메시지 전송을 마치면 연결을 끊어야 한다.
  • 신뢰적인 데이터 전송 서비스: 통신 프로세스는 모든 데이터를 오류 없이 올바른 순서로 전달하기 위해 TCP 에 의존한다. TCP 는 애플리케이션의 한 쪽이 바이트 스트림을 소켓으로 전달하면 그 바이트 스트림이 손실되거나 중복되지 않게 수신 소켓으로 전달한다.

또한 TCP 는 혼잡 제어 방식, 즉 통신하는 프로세스의 직접 이득보다는 인터넷의 전체 성능 향상을 위한 서비스를 포함한다.

UDP 서비스

UDP 는 최소의 서비스 모델을 가진 가장 간단한 전송 프로토콜이다.
UDP 는 비연결형이므로 두 프로세스가 통신을 하기 전에 핸드셰이킹을 하지 않는다.
UDP 는 비신뢰적인 데이터 전송 서비스를 제공한다. 즉, 하나의 프로세스가 UDP 소켓으로 메시지를 보내면, UDP 는 그 메시지가 수신 소켓에 도착하는 것을 보장하지 않는다. 게다가 수신 소켓에 도착하는 메시지들의 순서가 뒤바뀔 수도 있다.

UDP 는 혼잡 제어 방식을 포함하지 않는다. 따라서 UDP 의 송신 측은 데이터을 원하는 속도로 하위 계층(네트워크 계층)으로 보낼 수 있다.

인터넷 트랜스포트 프로토콜이 제공하지 않는 서비스

TCP 는 신뢰적 종단 간 데이터 전송을 제공하며, 보안 서비스를 제공하기 위해 애플리케이션 계층에서 TLS 를 통해 쉽게 강화될 수 있다.

그러나 TCP 와 UDP 에서 처리율 혹은 시간 보장에 대한 언급은 빠졌다.
그렇지만 인터넷은 여러 해 동안 시간 민감 애플리케이션을 서비스해오고 있고, 그런 보장이 없는 경우에도 가능한 한 잘 대처할 수 있도록 설계되었기 때문에 상당히 잘 작동하고 있다. 그럼에도 불구하고 현명한 설계도 공중 인터넷에서 흔히 있는 경우처럼 지연이 과도할 때는 한계가 있다.
즉, 오늘날의 인터넷은 때로 시간 민감 애플리케이션에게 만족스러운 서비스를 제공할 수는 있으나 시간 혹은 대역폭 보장을 제공할 수 없다.

인터넷 전화 애플리케이션은 보통 패킷 손실을 허용하지만 효율성을 위해 최소의 전송률을 필요로 하기 때문에 인터넷 전화 애플리케이션 개발자들은 일반적으로 UDP 상에서 자신들의 애플리케이션을 수행하는 것을 선호하며, 그렇게 함으로써 TCP 의 혼잡 제어 방식과 패킷 오버헤드를 회피할 수 있다. 그러나 많은 방화벽이 UDP 트래픽을 차단하도록 설정되어 있기 때문에, 인터넷 전화 애플리케이션은 UDP 통신이 실패할 경우를 대비하여 TCP 를 사용하도록 설계되어 있다.

애플리케이션 계층 프로토콜

애플리케이션 계층 프로토콜은 다른 종단 시스템에서 실행되는 애플리케이션의 프로세스가 서로 메시지를 보내는 방법을 정의한다.

  • 교환 메시지 타입 (ex. 요청 메시지와 응답 메시지)
  • 여러 메시지 타입의 문법 (ex. 메시지 내부의 필드와 필드 간의 구별 방법)
  • 필드의 의미, 즉 필드에 있는 정보의 의미
  • 언제, 어떻게 프로세스가 메시지를 전송하고 메시지에 응답하는지 결정하는 규칙

여러 애플리케이션 계층 프로토콜은 RFC에 명시되어 있으므로 공중 도메인에서 찾을 수 있다. ex. HTTP
다른 많은 애플리케이션 계층 프로토콜은 독점이며 (비개방적임) 공중 도메인에서 구할 수 없다.

애플리케이션 계층 프로토콜은 네트워크 애플리케이션의 한 요소일 뿐이다.

이 책에서 다루는 네트워크 애플리케이션

  • 전자메일
  • 디렉터리 서비스, DNS
  • P2P 애플리케이션, CDN

웹과 HTTP

HTTP 개요

웹의 애플리케이션 계층 프로토콜인 HTTP(HyperText Transfer Protocol) 은 웹의 중심이다.

HTTP 는 클라이언트 프로그램과 서버 프로그램으로 구현된다. 각기 다른 종단 시스템에서 수행되는 클라이언트와 서버 프로그램은 서로 HTTP 메시지를 교환하여 통신한다. HTTP 는 메시지의 구조 및 클라이언트와 서버가 메시지를 어떻게 교환하는지에 대해 정의하고 있다.

  • 웹 페이지는 객체들로 구성된다.
  • 객체는 단순히 단일 URL로 지정할 수 있는 하나의 파일이다.

대부분의 웹 페이지는 기본 HTML 파일과 여러 참조 객체로 구성된다.

http://www.someSchool.edu/someDepartment/picture.gif

여기에서 www.someSchool.edu 는 호스트 이름이고, /someDepartment/picture.gif 는 경로 이름이다.

웹 브라우저는 HTTP의 클라이언트 측을 구현하기 때문에 웹의 관점에서 브라우저와 클라이언트라는 용어를 혼용해서 사용할 것이다.
HTTP의 서버 측을 구현하는 웹 서버는 URL로 각각을 지정할 수 있는 웹 객체를 갖고 있다.

HTTP는 웹 클라이언트가 웹 서버에게 웹 페이지를 어떻게 요청하는지와 서버가 클라이언트로 어떻게 웹 페이지를 전송하는지를 정의한다.

HTTP는 TCP를 전송 프로토콜로 사용한다. HTTP 클라이언트는 먼저 서버에 TCP 연결을 시작한다. 연결이 이루어지면, 브라우저와 서버 프로세스는 그들의 소켓 인터페이스를 통해 TCP로 접속한다.
클라이언트 HTTP 요청 메시지를 소켓 인터페이스로 보내고 소켓 인터페이스로부터 HTTP 응답을 받는다. 마찬가지로 HTTP 서버는 소켓 인터페이스로부터 요청 메시지를 받고 응답 메시지를 소켓 인터페이스로 보낸다.
HTTP 는 데이터의 손실 또는 TCP가 어떻게 손실 데이터를 복구하고 네트워크 내부에서 데이터를 올바른 순서로 배열하는지 걱정할 필요가 없다. 이것은 TCP와 프로토콜 스택의 하위 계층들이 하는 일이다.

HTTP 서버는 클라이언트에 대한 정보를 유지하지 않으므로, HTTP를 **비상태 프로토콜 (stateless protocol)**이라고 한다.

현재 HTTP 트랜잭션의 대부분은 HTTP/1.1 을 사용하고 있지만, 점차 많은 브라우저와 웹 서버가 HTTP/2 를 지원하고 있다.

비지속 연결과 지속 연결

클라이언트-서버 상호작용이 TCP 상에서 발생할 때 애플리케이션 개발자는 중요한 결정을 해야 한다.
각 요구/응답 쌍이 분리된 TCP 연결을 통해 보내져야 하는가? 혹은 모든 요구와 해당하는 응답들이 같은 TCP 연결 상으로 보내져야 하는가?

전자 방식을 비지속 연결이라고 하고, 후자 방식을 지속 연결이라고 한다.
HTTP는 디폴트 모드로 지속 연결을 사용하지만 HTTP 클라이언트와 서버는 비지속 연결을 사용하도록 설정될 수 있다.

비지속 연결 HTTP

페이지가 기본 HTML 파일과 10개의 JPEG 이미지로 구성되고, 이 11개의 객체가 같은 서버에 있다고 가정하자.

http://www.someSchool.edu/someDepartment/home.index

연결 수행 과정은 다음과 같다.

  1. HTTP 클라이언트는 HTTP의 기본 포트 번호 80을 통해 www.someSchool.edu 서버로 TCP 연결을 시도한다. TCP 연결과 관련하여 클라이언트와 서버에 각각 소켓이 있게 된다.
  2. HTTP 클라이언트는 1단계에서 설정된 TCP 연결 소켓을 통해 서버로 HTTP 요청 메시지를 보낸다. 이 요청 메시지는 /someDepartment/home.index 경로 이름을 포함한다.
  3. HTTP 서버는 1단계에서 설정된 연결 소켓을 통해 요청 메시지를 받는다. 저장 장치로부터 /someDepartment/home.index 객체를 추출한다. HTTP 응답 메시지에 그 객체를 캡슐화한다. 그리고 응답 메시지를 소켓을 통해 클라이언트로 보낸다.
  4. HTTP 서버는 TCP 에게 TCP 연결을 끊으라고 한다. (그러나 실제로 TCP 클라이언트가 응답 메시지를 올바르게 받을 때까지 연결을 끊지 않는다.)
  5. HTTP 클라이언트가 응답 메시지를 받으면, TCP 연결이 중단된다. 메시지는 캡슐화된 객체가 HTML 파일인 것을 나타낸다. 클라이언트는 응답 메시지로부터 파일을 추출하고 HTML 파일을 조사하고 10개의 JPEG 객체에 대한 참조를 찾는다.
  6. 그 이후에 참조되는 각 JPEG 객체에 대해 처음 네 단계를 반복한다.
TCP 클라이언트가 응답 메시지를 올바르게 받을 때까지 연결을 끊지 않는 이유는 신뢰성 있는 데이터 전송을 보장하기 위해서이다. 

서버가 연결을 끊기 전에 클라이언트가 모든 데이터 패킷을 올바르게 받았는지 확인해야 한다. 

HTTP/1.0 은 비지속 연결을 지원한다. 각 TCP 연결은 하나의 요청 메시지와 하나의 응답 메시지만 전송한다. 따라서 이 예시에서는 사용자가 웹 페이지를 요청할 때 11개의 TCP 연결이 만들어진다.

클라이언트가 기본 HTML 파일을 요청하고 그 파일이 클라이언트로 수신될 때까지의 시간을 측정해보자. 이를 위해 작은 패킷이 클라이언트로부터 서버까지 가고, 다시 클라이언트로 되돌아오는 데 걸리는 시간인 RTT (round-trip time) 를 정의한다.
RTT는 패킷 전파 지연, 중간 라우터와 스위치에서의 패킷 큐잉 지연, 패킷 처리 지연 등을 포함한다.

사용자가 하이퍼링크를 클릭하면 브라우저가 브라우저와 웹 서버 사이에 TCP 연결을 시도하게 한다. 이는 three-hand way shake 를 포함한다. 즉, 클라이언트가 작은 TCP 메시지를 서버로 보내고, 서버는 작은 메시지로 응답하고, 마지막으로 클라이언트가 다시 서버에게 응답한다. (91p 참고) 따라서 총 응답 시간은 2 RTT와 HTML 파일을 서버가 전송하는 데 걸리는 시간을 더한 것이다.

지속 연결 HTTP

비지속 연결은 몇 가지 단점이 있다.

  1. 각 요청 객체에 대한 새로운 연결이 설정되고 유지되어야 한다. TCP 버퍼가 할당되어야 하고, TCP 변수들이 클라이언트와 서버 양쪽에 유지되어야 한다. 이는 수많은 클라이언트 요청을 동시에 서비스하는 웹 서버에게 심각한 부담을 줄 수 있다.
  2. 앞서 언급한 대로 각 객체는 2 RTT를 필요로 한다.

HTTP/1.1 지속 연결에서 서버는 응답을 보낸 후에 TCP 연결을 그대로 유지한다. 같은 클라이언트와 서버 간의 이후 요청과 응답은 같은 연결을 통해 보내진다. 특히, 전체 웹 페이지를 하나의 지속 TCP 연결을 통해 보낼 수 있다. 또한 같은 서버에 있는 여러 웹 페이지들을 하나의 지속 TCP 연결을 통해 보낼 수 있다.
이들 객체에 대한 요구는 여러 웹 페이지들을 하나의 지속 TCP 연결을 통해 보낼 수 있다.

일반적으로 HTTP 서버는 일정 기간(타임 아웃 기간) 사용되지 않으면 연결을 닫는다. 서버가 연속된 요구를 수신할 때, 서버는 객체를 연속해서 보낸다. HTTP의 디폴트 모드는 파이프라이닝을 이용한 지속 연결을 사용한다.

HTTP 메시지 포맷

HTTP 요청 메시지

GET /somedir/page.html HTTP/1.1
Host: www.someshool.edu
Connection: close
User-agent: Mozilla/5.0
Accept-language: fr

HTTP 요청 메시지의 첫 줄은 요청 라인이라고 하고, 이후의 줄들을 헤더 라인이라고 부른다.
요청 라인은 3개의 필드, 즉 method 필드, URL 필드, HTTP 버전 필드를 갖는다.
방식 필드는 GET, POST, HEAD, PUT, DELETE 를 포함하는 여러 가지 값을 가질 수 있다.

Host 는 객체가 존재하는 호스트를 명시하고 있다. 호스트 헤더 라인이 제공하는 정보는 웹 프록시 캐시에서 필요로 한다. Connection 은 브라우저가 서버에게 지속 연결 사용을 원하지 않는다는 것을 말하고 있다.
User-agent 는 서버에게 요청하는 브라우저 타입을 명시하고 있다.
Accept-language 헤더는 사용자가 객체의 프랑스어 버전을 원하고 있음을 나타낸다. 이것이 존재하지 않으면 서버는 기본 버전을 보낸다.

HEAD 방식을 가진 요청을 받으면 HTTP 메시지로 응답하는데, 요청 객체는 보내지 않는다.
애플리케이션 개발자는 흔히 디버깅을 위해 HEAD 방식을 많이 사용한다. PUT 방식은 웹 서버에 업로드할 객체를 필요로 하는 애플리케이션에 의해 사용된다.
DELETE 방식은 사용자 또는 애플리케이션이 웹 서버에 있는 객체를 지우는 것을 허용한다.

HTTP 응답 메시지

HTTP/1.1 200 OK
Connection: close
Date: Tue, 18 Aug 2015 15:44:05 GMT
Server: Apache/2.2.3 (CentOS)
Last-Modified: Tue, 18 Aug 2015 15:11:03 GMT
Content-Length: 6821
Content-Type: text/html

(데이터 데이터 데이터 데이터 데이터 ...)

초기 상태 라인, 6개의 헤더 라인, 개체 몸체로 이루어져 있다.
개체 몸체는 요청 객체를 포함한다.
상태 라인은 3개의 필드, 즉 프로토콜 ‘버전 필드’, ‘상태 코드’, ‘해당 상태 메시지’를 갖는다.
상태 라인은 서버가 HTTP/1.1 을 사용하고 있고, 모든 것이 양호함을 나타낸다.

  1. Connection: 클라이언트에게 메시지를 보낸 후 TCP 연결을 닫는 데 사용
  2. Date: HTTP 응답이 서버에 의해 생성되고 보낸 날짜와 시간을 나타낸다. 서버가 파일 시스템으로부터 객체를 추출하고 응답 메시지에 그 객체를 삽입하여 응답 메시지를 보낸 시간을 의미한다.
  3. Server: 메시지가 아파치 웹 서버에 의해 만들어졌음을 나타낸다.
  4. Last-Modified: 객체가 생성되거나 마지막으로 수정된 시간과 날짜를 나타낸다. 객체를 로컬 클라이언트와 네트워크 캐시 서버 캐싱에 매우 중요하다.
  5. Content-Length: 송신되는 객체의 바이트 수를 나타낸다.
  6. Content-Type: 개체 몸체 내부의 객체가 HTML 텍스트인 것을 나타낸다.

사용자와 서버 간의 상호작용: 쿠키

서버가 사용자 접속을 제한하거나 사용자에 따라 콘텐츠를 제공하기 원하므로 웹사이트가 사용자를 확인하는 것이 바람직할 때가 있다. 이를 위해 HTTP 는 쿠키를 사용한다.

쿠키 기술은 다음과 같은 요소들을 가지고 있다.

  1. HTTP 응답 메시지 쿠키 헤더 라인
  2. HTTP 요청 메시지 쿠키 헤더 라인
  3. 사용자의 브라우저에 사용자 종단 시스템과 관리를 지속시키는 쿠키 파일
  4. 웹사이트의 백엔드 데이터베이스

HTTP 응답 메시지에 Set-Cookie 헤더는 식별 번호를 담는다. HTTP 요청에는 Cookie 에 쿠키의 식별 번호를 포함하는 쿠키 헤더 파일을 넣는다.

쿠키는 사용자 식별에 사용할 수 있다. 즉, 비상태 HTTP 위에서 사용자 세션 계층을 생성하는 데 이용될 수 있다.

웹 캐싱

웹 캐시 (프록시 서버) 는 기점 웹 서버를 대신하여 HTTP 요구를 충족시키는 네트워크 개체다. 웹 캐시는 자체의 저장 디스크를 갖고 있어 최근 호출된 객체의 사본을 저장 및 보존한다.

  1. 브라우저는 웹 캐시와 TCP 연결을 설정하고 웹 캐시에 있는 객체에 대한 HTTP 요청을 보낸다.
  2. 웹 캐시는 객체의 사본이 자신에게 저장되어 있는지 확인한다. 만일 저장되어 있다면 웹 캐시는 클라이언트 브라우저로 HTTP 응답 메시지와 함께 객체를 전송한다.
  3. 만약 웹 캐시가 객체를 갖고 있지 않으면, 웹 캐시는 기점 서버로 TCP 연결을 설정한다. 웹 캐시는 캐시와 서버 간의 TCP 연결로 객체에 대한 HTTP 요청을 보낸다. 이런 요청을 받은 후에 기점 서버는 웹 캐시로 HTTP 응답 메시지와 함께 객체를 보낸다.
  4. 웹 캐시의 객체를 수신할 때, 객체를 지역 저장장치에 복사하고 클라이언트 브라우저에 HTTP 응답 메시지와 함께 객체의 사본을 보낸다.

캐시는 서버이면서 클라이언트이다.
일반적으로 웹 캐시는 ISP 가 구입하고 설치한다.

웹 캐시는 클라이언트의 요구에 대한 응답 시간을 줄일 수 있다. 특히 클라이언트와 기점 서버 사이의 병목 대역폭이 클라이언트와 캐시 사이의 병목 대역폭에 비해 매우 작을 때 더욱 효과적이다.
웹 캐시는 한 기관에서 인터넷으로의 접속하는 링크상의 웹 트래픽을 대폭 줄일 수 있다. 또한 웹 캐시는 인터넷 전체의 웹 트래픽을 실질적으로 줄임으로써 모든 애플리케이션을 위한 성능을 개선한다.

콘텐츠 전송 네트워크 (Content Distribution Network, CDN) 의 사용을 통해 웹 캐시는 인터넷에서 점진적으로 중요한 역할을 하고 있다. CDN 회사는 인터넷 전역을 통해 많은 지역적으로 분산된 캐시를 설치하고 있으며, 이를 통해 많은 트래픽을 지역화하고 있다.

조건부 GET

웹 캐싱은 사용자가 느끼는 응답 시간을 줄일 수 있지만, 새로운 문제를 야기한다. 캐시 내부에 있는 객체의 복사본이 새 것이 아닐 수 있다는 것이다.

HTTP 는 클라이언트가 브라우저로 전달되는 모든 객체가 최신의 것임을 확인하면서도 캐싱을 하게 해주는 방식을 갖고 있다. 이를 조건부 GET 이라고 한다.

HTTP 요청 메시지가 GET 방식을 사용하고, If-Modified-Since 헤더라인을 포함하고 있다면, 조건부 GET 메시지이다.

조건부 GET 은 다음과 같이 동작한다.

  1. 브라우저의 요청을 대신해 프록시 캐시는 요청 메시지를 웹 서버로 보낸다.
  2. 웹 서버는 캐시에게 객체를 가진 응답 메시지를 보낸다.
  3. 캐시는 요청하는 브라우저에게 객체를 보내주고 자신에게도 객체를 저장한다. 캐시는 객체와 더불어 마지막으로 수정된 날짜를 함께 저장한다.
  4. 브라우저는 조건부 GET으로 갱신 조사를 수행한다. If-modified-since: Wed, 9 Sep 2015 09:23:24 의 헤더 라인을 보냈을 때 웹 서버가 응답 메시지에 요청된 객체를 포함하지 않는 경우, 이는 클라이언트에게 요청 객체의 캐싱된 복사본을 사용하라는 것을 의미한다.

HTTP/2

2015년에 표준화된 HTTP/2 는 1997년에 표준화된 HTTP/1.1 이후 새로운 첫 번째 HTTP 버전이다.

HTTP/2의 주요 목표는 하나의 TCP 연결 상에서 멀티플렉싱 요청/응답 지연 시간을 줄이는 데 있으며, 요청 우선순위화, 서버 푸시, HTTP 헤더 필드의 효율적인 압축 기능 등을 제공한다. 클라이언트와 서버 간의 데이터 포맷 방법과 전송 방법도 변경되었다.

HTTP/1.1은 지속적인 TCP 연결을 이용하여 하나의 TCP 연결 상에서 서버로부터 클라이언트로 보내지는 웹 페이지를 허용한다. 웹 페이지당 오직 하나의 TCP 연결을 가짐으로써, 서버의 소켓 수를 줄이며 전송되는 각 웹 페이지는 공정한 데이터 대역폭을 가질 수 있다.

그러나 하나의 TCP 상에서 웹 페이지에 있는 모든 객체를 보내면 HOL (Head of Line) 블로킹 문제가 발생할 수 있다.

큰 비디오 클립이 위치하고, 비디오 아래 많은 수의 작은 객체들을 포함하는 하나의 웹 페이지를 생각해보자. 또한 서버와 클라이언트 사이에 저속에서 중간 속도의 병목 링크가 있다고 가정했을 때, 하나의 TCP 연결을 사용하면 비디오 클립은 병목 링크를 통과하는 데 오랜 시간이 걸리지만 작은 객체들은 비디오 객체 뒤에서 기다림이 길어진다. 즉, 비디오 클립이 뒤에 오는 작은 객체들을 블로킹하게 되는 것이다.

HTTP/1.1 브라우저에서는 여러 개의 병렬 TCP 연결을 열어서 HOL 블로킹 문제를 해결해왔다. TCP 혼잡 제어 또한 하나의 지속적인 연결 대신 여러 개의 병렬 TCP 연결을 사용함으로써 브라우저에게 예상치 못한 혜택을 주게 된다. TCP 혼잡 제어는 각 TCP 연결이 공정하게 병목 링크를 공유하여 같은 크기의 가용한 대역폭을 공평하게 나누게 해준다. 많은 HTTP/1.1 브라우저들은 6개까지 병렬 TCP 연결을 열 수 있으며 HOL 블로킹을 막을 뿐만 아니라 더 많은 대역폭을 사용할 수 있게 해준다.

HTTP/2 의 주요 목표는 하나의 웹 페이지를 전송하기 위한 병렬 TCP 연결의 수를 줄이거나 제거하는 데 있다.

HTTP/2 의 프레이밍

HTTP/2는 각 메시지를 작은 프레임으로 나누고, 같은 TCP 연결에서의 요청과 응답 메시지를 인터리빙한다. HTTP 메시지를 독립된 프레임으로 쪼개고 인터리빙하고 반대편 사이트에서 재조립하는 것이야말로 HTTP/2의 가장 중요한 개선점이다.

프레이밍은 HTTP/2 프로토콜의 프레임으로 구현된 다른 프레이밍 서브 계층에 의해 이루어진다. 응답은 프레이밍 서브 계층에 의해 처리되며 프레임들로 나눠지고, 응답의 헤더 필드는 하나의 프레임이 되며 메시지 본문은 하나의 프레임으로 쪼개진다. 응답 프레임들은 서버의 프레이밍 서브 계층에 의해 인터리빙된 후 하나의 지속적인 TCP 연결상에서 전송된다. 프레임들이 클라이언트에 도착하면 프레이밍 서브 계층에서 처음 응답 메시지로 재조립되며 브라우저에 의해 처리된다.

프레이밍 서브 계층은 파싱 효율성과 작은 프레임 크기, 에러에 강건한 구조를 위해 프레임을 바이너리 인코딩한다.

메시지 우선순위화 및 서버 푸싱

메시지 우선순위화는 개발자들로 하여금 요청들의 상대적 우선순위를 조정할 수 있게 함으로써 애플리케이션의 성능을 최적화할 수 있도록 해준다.

클라이언트가 한의 특정 서버로 동시에 여러 개의 요청을 할 때, 각 메시지에 1~256 사이의 가중치를 부여함으로써 요청에 우선순위를 매길 수 있다. (높은 숫자일수록 높은 우선순위를 의미한다.) 서버는 가장 높은 우선순위의 요청을 위한 프레임을 제일 먼저 보낼 수 있고, 클라이언트 역시 각 의존도에 따라 메시지의 ID를 지정함으로써 서로 다른 메시지들 간의 의존성을 나타낼 수 있다.

HTTP/2는 서버로 하여금 특정 클라이언트 요청에 대해 여러 개의 응답을 보낼 수 있게 해준다. 처음 요청에 대한 응답 외에도, 서버는 클라이언트의 요청 없이도 추가적인 객체를 클라이언트에게 푸시하여 보낼 수도 있다.

HTTP/3

QUIC 은 UDP 프로토콜 위에 위치하는 애플리케이션 계층에 구현된 새로운 트랜스포트 프로토콜이다. 메시지 멀티플렉싱(인터리빙), 스트림별 흐름 제어, 저지연 연결 확립과 같은 HTTP 에 의미 있는 여러 특징을 갖는다. HTTP/3 은 QUIC 위에서 작동하도록 설계된 새로운 HTTP 프로토콜이다.

인터넷 전자메일

인터넷 메일 시스템은 사용자 에이전트, 메일 서버, SMTP 라는 3가지의 주요 요소를 갖는다.

사용자 에이전트는 사용자가 메시지를 읽고, 응답하고, 전달하고, 저장하고, 구성하게 해준다.

메일 서버는 전자메일 인프라스트럭처의 중심이다. 수신자는 메일 서버 안에 메일박스를 갖고 있고, 메일박스는 수신자의 메시지를 유지하고 관리한다. 일반 메시지는 송신자의 사용자 에이전트에서 전달되고, 송신자의 메일 서버를 거친 후에 수신자의 메일 서버로 전달된 후, 수신자의 메일박스에 저장된다. 수신자의 메일 서버가 고장난 경우, 송신자의 메일 서버는 메시지를 메시지 큐에 보관하고 메시지를 전달하기 위해 재시도한다.

SMTP 는 인터넷 전자메일을 위한 주요 애플리케이션 계층 프로토콜이다. SMTP 는 TCP 의 신뢰적인 데이터 전송 서비스를 이용한다.

SMTP

SMTP 는 송신자의 메일 서버로부터 수신자의 메일 서버로 메시지를 전송한다.
SMTP는 여러 장점이 있으나, 낡은 특성을 가진 오래된 기술이다. 그 중 하나로, 모든 메일 메시지의 몸체는 단순한 7비트 ASCII여야 한다는 단점이 있다.

SMTP 는 다음과 같이 동작한다.

  1. 송신자는 전자메일 사용자 에이전트를 수행하고 수신자의 전자메일 주소를 제공하고, 메시지를 작성한 뒤 사용자 에이전트에게 메시지를 보내라고 명령한다.
  2. 송신자의 사용자 에이전트는 메시지를 수신자의 메일 서버에게 보내고, 메시지는 메시지 큐에 놓인다.
  3. 송신자의 메일 서버에서 동작하는 SMTP 의 클라이언트 측은 메시지 큐에 있는 메시지를 본다. 수신자의 메일 서버에서 수행되고 있는 SMTP 서버에게 TCP 연결을 설정한다.
  4. 초기 SMTP 핸드셰이킹 이후에 SMTP 클라이언트는 송신자의 메시지를 TCP 연결로 보낸다.
  5. 수신자의 메일 서버 호스트에서 SMTP 서버 측은 메시지를 수신한다. 수신자의 메일 서버는 그 메시지를 수신자의 메일박스에 놓는다.
  6. 수신자는 편한 시간에 그 메시지를 읽기 위해 사용자 에이전트를 시동한다.

SMTP 는 메시지를 송신 메일 서버에서 수신 메일 서버로 어떻게 전송할까?

  1. 클라이언트 SMTP 는 서버 SMTP 의 25번 포트로 TCP 연결을 설정한다. 연결이 설정되면, 서버와 클라이언트는 애플리케이션 계층 핸드셰이킹을 수행한다.
  2. SMTP 핸드 셰이킹 과정 동안에 SMTP 클라이언트는 송신자의 전자메일 주소와 수신자의 전자메일 주소를 제공한다.
  3. 클라이언트는 메시지를 전송한다.
  4. SMTP는 서버에 오류 없이 메시지를 전송하기 위해 TCP 의 신뢰적인 데이터 전송 서비스에 의존한다.
  5. 서버에 보낼 다른 메시지가 있으면 클라이언트는 이 과정을 같은 TCP 연결 상에서 반복하고, 그렇지 않으면 TCP 에게 연결을 닫을 것을 명령한다.

클라이언트는 HELO, MAIL FROM, RCPT TO, DATA, QUIT 명령을 내린다. 또한 클라이언트가 하나의 점으로 된 라인을 송신하면, 메시지의 끝을 의미한다.

SMTP 는 지속 연결을 사용한다. 송신 메일 서버가 같은 수신 메일 서버로 보내는 여러 메시지를 갖고 있다면, 같은 TCP 연결을 통해 모든 메시지를 전달할 수 있다.

메일 메시지 포맷

헤더 라인과 메시지 몸체는 빈 줄(CRLF)로 분리된다. 각 헤더라인은 키워드, 콜론, 값의 순서로 구성되고 읽을 수 있는 텍스트를 포함한다.

모든 헤더는 From 헤더와 To 헤더를 반드시 가져야 한다.

메일 접속 프로토콜

전자메일 메시지가 송신자 사용자 에이전트로부터 수신자 메일 서버로 전송될 때, 전자메일 메시지는 어떤 경로를 가지게 될까?

송신자의 사용자 에이전트는 송신자의 메일 서버로 전자메일 메시지를 SMTP 또는 HTTP 를 통해 보낸다. 또한 송신자의 메일 서버는 SMTP 를 사용하여 수신자의 메일 서버로 전자메일 메시지를 중계한다. 송신자의 메일 서버를 통해 중계하지 않으면, 송신자의 사용자 에이전트는 목적지 메일 서버에 도달할 수 없다.
송신자의 메일 서버는 수신자의 메일 서버로 30분마다 반복해서 보내려고 한다.

로컬호스트 PC에서 사용자 에이전트를 수행하는 수신자는 자신의 ISP 내부의 메일 서버에 있는 자신의 메시지를 어떻게 얻을 수 있을까? 수신자의 사용자 에이전트는 메시지를 얻기 위해 SMTP 를 사용할 수 없다. 이는 SMTP 가 푸시 프로토콜인 반면, 메시지를 얻는 것은 풀 동작이기 때문이다.

수신자가 메시지를 얻는 방법은 두 가지가 있다. 첫 번째는 웹 기반 전자메일 등을 사용하고 있다면 사용자 에이전트는 수신자의 전자메일을 확인하기 위해 HTTP를 사용할 것이다. 이 경우, 수신자의 메일 서버는 송신자의 메일 서버와 통신하기 위해 SMTP 인터페이스는 물론이고 HTTP 인터페이스를 갖고 있어야 한다.
두 번째는 메일 클라이언트를 사용하는 방법인데, RFC 3501 에 정의된 인터넷 메일 접근 프로토콜 (Internet Mail Access Protocol, IMAP) 을 사용하게 된다.

DNS: 인터넷의 디렉터리 서비스

인터넷 호스트의 식별자 중 하나는 호스트 이름이다. 호스트는 흔히 말하는 IP 주소로도 식별된다.

DNS가 제공하는 서비스

사람은 기억하기 쉬운 호스트 이름 식별자를 좋아하지만, 라우터는 고정 길이의 계층 구조를 가진 IP 주소를 좋아한다. 이를 절충하기 위해 호스트 이름을 IP 주소로 변환해주는 디렉터리 서비스가 필요하다. 이것이 인터넷 DNS 의 주요 임무다.

DNS는 DNS 서버들의 계층구조로 구현된 분산 데이터베이스이고, 호스트가 분산 데이터베이스로 질의하도록 허락하는 애플리케이션 계층 프로토콜이다.

DNS 서버는 주로 BIND(Berkeley Internet Name Domain) 소프트웨어를 수행하는 유닉스 컴퓨터다. DNS 프로토콜은 UDP 상에서 수행되고, 포트번호 53을 이용한다.

DNS는 다른 애플리케이션 프로토콜들이 HTTP, SMTP, FTP 등 사용자가 제공한 호스트 이름을 IP 주소로 변환하기 위해 주로 이용한다. 다음과 같이 수행된다.

  1. 같은 사용자 컴퓨터는 DNS 애플리케이션의 클라이언트 측을 수행한다.
  2. 브라우저는 URL로부터 호스트 이름을 추출하고 그 호스트 이름을 DNS 애플리케이션의 클라이언트 측에 넘긴다.
  3. DNS 클라이언트는 DNS 서버로 호스트 이름을 포함하는 질의로 보낸다.
  4. DNS 클라이언트는 결국 호스트 이름에 대한 IP 주소를 가진 응답을 받게 된다.
  5. 브라우저가 DNS로부터 IP 주소를 받으면, 브라우저는 해당 IP 주소와 그 주소의 80 번 포트에 위치하는 HTTP 서버 프로세스로 TCP 연결을 초기화한다.

DNS 는 호스트 이름을 IP 주소로 변환하는 것 이외에 다음과 같은 중요한 추가 서비스를 제공한다.

  1. host aliasing: 복잡한 호스트 이름을 가진 호스트는 하나 이상의 별명을 가질 수 있다. DNS는 호스트의 IP 주소 뿐만 아니라 제시한 별칭 호스트 이름에 대한 정식 호스트 이름을 얻기 위해 이용될 수 있다.
  2. 메일 서버 aliasing: 전자메일 주소는 기억하기 쉬운 것이 좋다. DNS는 호스트의 IP 주소 뿐만 아니라 제공된 별칭 호스트 이름에 대한 정식 호스트 이름을 얻기 위해 메일 애플리케이션에 의해 수행된다.
  3. 부하 분산: DNS는 중복 웹 서버 같은 여러 중복 서버 사이에 부하를 분산하기 위해서도 사용되고 있다. 중복 웹 서버의 경우, 여러 IP 주소가 하나의 정식 호스트 이름과 연관되어 있는데, DNS 데이터베이스는 이 IP 주소 집합을 가지고 있다. 클라이언트가 주소 집합으로 매핑하는 호스트 이름에 대한 DNS 질의를 하면, 서버는 IP 주소 집합 전체를 가지고 응답한다. 각 응답에서의 주소는 순환식으로 보낸다. 클라이언트는 대체로 주소 집합 내부의 첫 번째 IP 주소로 HTTP 요청 메시지를 보내므로, DNS 의 순환 방식은 여러 중복 서버들 사이에서 트래픽을 분산하는 효과를 낸다.

DNS 동작 원리 개요

DNS는 전 세계에 분산된 많은 DNS 서버 뿐만 아니라 DNS 서버와 질의하는 호스트 사이에서 어떻게 통신하는지를 명시하는 애플리케이션 계층 프로토콜로 구성되어 있다.

DNS 의 간단한 설계로 모든 매핑을 포함하는 하나의 인터넷 네임 서버를 생각할 수 있다.
중앙 집중 방식에서 클라이언트는 모든 질의를 단일 네임 서버로 보내고, DNS 서버는 질의 클라이언트에게 직접 응답한다. 이 방식의 문제점은 다음과 같다.

  1. 서버 고장: 네임 서버가 고장나면, 전체 인터넷이 동작하지 않는다.
  2. 트래픽 양: 단일 DNS 서버가 모든 DNS 질의를 처리해야 한다.
  3. 먼 거리의 중앙 집중 데이터베이스: 단일 DNS 서버가 모든 질의 클라이언트로부터 가까울 수만은 없다. 이는 심각한 지연을 발생시킬 수 있다.
  4. 유지 관리: 중앙 집중 데이터베이스는 거대해지고 모든 새로운 호스트를 반영하기 위해 자주 갱신되어야만 한다. 또한 중앙 집중 데이터베이스에 호스트를 등록할 수 있도록 사용자에게 허용하는 것과 관련된 인증 문제가 있다.

즉, 단일 DNS 서버에 있는 중앙 집중 데이터베이스는 확장성이 전혀 없다.

분산 계층 데이터베이스

DNS는 많은 서버를 이용하고 이들을 계층 형태로 구성하여 전 세계에 분산시킨다.
여기에는 계층으로 구성된 세 유형의 DNS 서버가 존재한다.

  1. 루트 DNS 서버 1000개 이상의 루트 서버 인스턴스가 전 세계에 흩어져 있다. 루트 서버들은 13개의 다른 루트 서버 복사체이고, 12개의 다른 기관에서 관리되며, 인터넷 할당 번호 관리기관에 의해 조정된다.
  2. 최상위 레벨 도메인 네임 (top-level domain, TLD) DNS 서버 com, org, net, edu, gov 같은 상위 레벨 도메인과 kr, uk, fr, ca, jp 같은 모든 국가의 상위 레벨 도메인에 대한 TLD 서버 (또는 서버 클러스터)가 있다. TLD 서버는 책임 DNS 서버에 대한 IP 주소를 제공한다.
  3. 책임(authoritative) DNS 서버 인터넷에서 접근하기 쉬운 호스트를 가진 모든 기관은 호스트 이름을 IP 주소로 매핑하는 공개적인 DNS 레코드를 제공해야 한다. 기관의 책임 DNS 서버는 이 DNS 레코드를 가지고 있다. 또한 기관은 이 레코드를 갖도록 자신의 책임 DNS 서버의 구현을 선택할 수 있고, 일부 서비스 제공자의 책임 DNS 서버에 이 레코드를 저장하도록 비용을 지불한다.

DNS 의 또 다른 중요한 형태 중 로컬 DNS 서버가 있다.
ISP 들은 로컬 DNS 서버를 갖는다. 호스트가 ISP 에 연결될 때, ISP 는 로컬 DNS 서버로부터 IP 주소를 호스트에게 제공한다 (DHCP 를 통해).
호스트가 DNS 질의를 보내면, 이 질의는 먼저 프록시로 동작하는 로컬 DNS 서버에 전달되고, 로컬 DNS 서버는 이 질의를 DNS 서버 계층으로 전달한다.

이전 예시에서 TLD 서버는 호스트 이름에 대한 책임 서버를 안다고 가정했지만, 일반적으로는 그렇지 않다. 대신에 TLD 서버는 호스트 이름에 대한 책임 DNS 를 아는 중간 DNS 서버만을 알고 있다.

이론상, DNS 질의는 반복적이고, 재귀적일 수 있다. 요청하는 호스트로부터 로컬 DNS 서버까지의 질의는 재귀적이고, 나머지 질의는 반복적이다.

DNS 캐싱

DNS 는 지연 성능 향상과 네트워크의 DNS 메시지 수를 줄이기 위해 캐싱을 사용한다.
질의 사슬에서 DNS 서버가 DNS 응답을 받을 때, 로컬 메모리에 응답에 대한 정보를 저장할 수 있다. 호스트 DNS 와 IP 주소 사이의 매핑과 호스트는 영구적인 것이 아니기 때문에 DNS 서버는 어떤 기간 (흔히 2일) 이후에 저장된 정보를 제거한다.

캐싱으로 인해 로컬 DNS 서버는 두 번째로 질의한 호스트에게 다른 DNS 서버로의 질의 없이 즉시 IP 주소를 보낼 수 있다. 로컬 DNS 서버는 또한 TLD 서버의 IP 주소를 저장할 수 있기 때문에, 이는 로컬 DNS 서버가 질의 사슬에서 루트 DNS 서버를 우회할 수 있도록 한다.

DNS 레코드와 메시지

DNS 분산 데이터베이스를 구현한 DNS 서버들은 호스트 이름을 IP 주소로 매핑하기 위한 자원 레코드 (Resource Record, RR) 을 저장한다.
각 DNS 는 하나 이상의 자원 레코드를 가진 메시지로 응답한다.

자원 레코드는 다음과 같은 필드를 포함하는 4개의 튜플로 되어 있다.

(Name, Value, Type, TTL)

TTL 은 자원 레코드가 캐시에서 제거되는 시간을 결정한다.
Name 과 Value 의 의미는 Type 에 따른다.

  • Type이 A이면, Name 은 호스트 이름이고 Value는 호스트 이름에 대한 IP 주소다. 즉, Type A 레코드는 표준 호스트 이름의 IP 주소 매핑을 제공한다.
    • (relay1.bar.foo.com, 145.37.93.126, A)
  • Type이 NS면, Name 은 도메인이고 Value 는 도메인 내부의 호스트에 대한 IP 주소를 얻을 수 있는 방법을 아는 책임 DNS 서버의 호스트 이름이다.
    • (foo.com, dns.foo.com, NS)
  • Type 이 CNAME 이면, Value 는 별칭 호스트 이름 Name 에 대한 정식 호스트 이름이다. 이 레코드는 질의 호스트에게 호스트 이름에 대한 정식 이름을 제공한다.
    • (foo.com, relay1.bar.foo.com, CNAME)
  • Type이 MX 이면, Value 는 별칭 호스트 이름 Name 을 갖는 메일 서버의 정식 이름이다.
    • (foo.com, mail.bar.foo.com, MX)

한 DNS 서버가 특별한 호스트 이름에 대한 책임 서버이면, 그 DNS 서버는 그 호스트 이름에 대한 Type A 레코드를 포함한다. 서버가 호스트 이름에 대한 책임 서버가 아니라면 그 서버는 호스트 이름을 포함하는 도메인에 대한 Type NS 레코드를 포함할 것이고, NS 레코드의 Value 필드에 DNS 서버의 IP 주소를 제공하는 Type A 레코드도 포함할 것이다.

DNS 메시지

DNS 메시지 내부의 여러 필드의 의미는 다음과 같다.

  • 처음 12바이트는 헤더 영역으로, 여러 필드를 갖고 있다.
    • 첫 필드는 질의를 식별하는 16비트 숫자다. 이 식별자는 질의에 대한 응답 메시지에 복사되어, 클라이언트가 보낸 질의와 수신된 응답 간의 일치를 식별하게 한다. 플래그 필드에는 여러 개의 플래그가 있다.
      • 1비트의 질의/응답 플래그는 메시지가 질의(0) 인지 응답(1)인지를 구별하게 한다.
      • 1비트의 책임 플래그는 DNS 서버가 질의 이름에 대해 책임 서버일 때 응답 메시지에 설정된다.
      • 1비트의 재귀 요구 플래그는 DNS 서버가 레코드를 갖지 않을 때 재귀적 질의를 수행하기를 클라이언트가 원할 때 설정된다.
    • 1비트로 된 재귀 가능 필드는 DNS 서버가 재귀 질의를 지원하면 응답에 설정된다. 헤더에 4개의 ‘개수’ 필드가 있다. 이들 필드는 헤더 다음에 오는 데이터 영역의 네 가지 타입의 발생 횟수를 나타낸다.
      • 질문의 수, 답변 RR의 수, 추가 RR의 수, 추가 RR의 수
  • 질문 영역은 현재 질의에 대한 정보를 포함한다. 이 영역은 질의되는 이름을 포함하는 이름 필드와, 이름에 대해 문의되는 질문 타입을 나타내는 타입 필드를 포함한다.
  • DNS 서버로부터의 응답에서 답변 영역은 원래 질의된 이름에 대한 자원 레코드를 포함한다. 응답으로 여러 개의 RR을 보낼 수 있다. 호스트 이름은 여러 개의 IP 주소를 가질 수 있기 때문이다.
  • 책임 영역은 다른 책임 서버의 레코드를 포함한다.
  • 추가 영역은 다른 도움이 되는 레코드를 포함하고 있다.
    • MX 질의에 대한 응답에서 응답 필드는 전자메일 서버의 정식 호스트 이름을 제공하는 자원 레코드를 갖고 있다. 추가 영역은 메일 서버의 정식 호스트 이름에 대한 IP 주소를 포함하는 Type A 레코드를 포함한다.

어떻게 DNS 질의 메시지가 우리가 작업하는 호스트로부터 DNS 서버로 곧장 보내기 위해 nslookup 프로그램을 사용할 수 있다.

DNS 데이터베이스에 레코드 삽입

처음에 어떻게 레코드를 데이터베이스에 넣을까?

가장 먼저 도메인 네임을 등록기관에 등록한다. 등록기관은 도메인 네임의 유일성을 확인하고, 그 도메인 이름을 DNS 데이터베이스에 넣고, 그 서비스에 대한 약간의 요금을 우리로부터 받는 상업기관이다.

우리의 도메인 네임을 어떤 등록기관에 등록할 때, 등록 기관에 주책임 서버와 부책임 서버의 이름과 IP 주소를 등록기관에 제공해야 한다. 두 책임 DNS 서버 각각에 대해 등록 기관은 Type NS와 Type A 레코드가 TLD 서버에 등록되도록 확인한다.

이러한 단계가 끝나고 나면 사람들은 우리의 웹사이트를 방문할 수 있고 우리 회사의 직원들에게 전자메일을 보낼 수도 있다.

DNS 취약점

루트 DNS 서버에 대한 DDoS 대역폭 플러딩 공격, 모든 최상위 도메인 서버들에게 다량의 DNS 질의를 보내는 것, 중간자 공격, DNS 중독 공격 등 여러 공격으로부터 공격받을 잠재성이 존재한다. 

P2P 파일 분배

웹, 전자메일, DNS 등은 모두 항상 켜져 있는 인프라스트럭처 서버에 상당히 의존하는 클라이언트-서버 구조를 채택하고 있다. P2P 구조는 항상 켜져 있는 인프라스트럭처 서버에 최소한으로 의존한다. 대신 간헐적으로 연결되는 호스트 쌍들이 서로 직접 통신한다.

P2P 구조의 확장성

서버와 피어들이 접속 링크로 인터넷에 연결되어 있다고 가정하자.
서버의 접속 링크 업로드 속도 = usu_s i 번째 피어의 접속 링크 업로드 속도 = uiu_i i 번째 피어의 접속 링크 다운로드 속도 = did_i 분배되는 파일의 크기 = FF (bit) 파일의 복사본을 얻고자 하는 피어들의 수 = NN

분배 시간은 모든 N 개의 피어들이 파일의 복사본을 얻는 데 걸리는 시간이다.
클라이언트-서버와 P2P 구조 모두 인터넷 코어가 풍부한 대역폭을 갖고 있고, 또한 클라이언트-서버의 모든 업로드와 다운로드 접속 대역폭은 이 파일 분배에 모두 사용된다고 가정한다.

먼저 클라이언트-서버 구조에 대한 분배 시간 (DcsD_{cs}) 을 계산할 때 어떤 피어도 파일을 분배하는 데 도움을 줄 수 없다.

  • 서버는 파일 복사본을 N개의 피어 각각에게 전송해야 한다. 즉, 서버는 NFNF 비트를 전송해야 한다. 서버의 업로드 속도가 usu_s 이기 때문에 파일을 분배하는 시간은 적어도 NF/usNF/u_s 이다.
  • dmind_{min}이 가장 낮은 다운로드 속도를 가진 피어의 다운로드 속도를 나타낸다고 하자. 즉, dmin=min{d1,d2,...,dN}d_{min} = min\{d_1, d_2, ... , d_N\} 이다. 가장 낮은 다운로드 속도를 가진 피어는 F/dminF/d_{min} 초보다 적은 시간에 파일의 모든 F 비트를 얻을 수 없다. 따라서 최소 분배 시간은 적어도 F/dminF/d_{min} 이다.

이를 결합하면 다음과 같은 수식을 얻을 수 있다.
Dcsmax{NFus,Fdmin}D_{cs} \ge max \{ \frac{NF}{u_{s}} , \frac{F}{d_{min}}\}

이는 클라이언트-서버 구조에 대한 최소 분배 시간의 하한값을 제공한다.
충분히 큰 N에 대해 클라이언트-서버 분배 시간은 NF/usNF/u_s 로 주어진다는 사실을 알 수 있다. 즉, 분배 시간은 N에 따라 선형적으로 증가한다.

P2P 구조에서는 각 피어들이 서버가 파일을 분배하는 데 도움을 줄 수 있다.
특히 한 피어가 파일 데이터 일부를 수신할 때, 피어는 그 데이터를 다른 피어들에게 재분배하는 데 자신의 업로드 용량을 이용할 수 있다.

  • 분배가 시작되면 서버만이 파일을 갖고 있다. 이 파일이 피어 커뮤니티에 도달할 수 있도록 하기 위해 서버는 적어도 한 번 접속 링크로 파일의 각 비트를 보내야 한다. 즉, 최소 분배 시간은 적어도 F/usF/u_s이다.
  • 클라이언트-서버 구조와 마찬가지로 다운로드 속도가 가장 낮은 피어는 F/dminF/d_{min} 초보다 적은 시간 안에 파일의 모든 F 비트를 받을 수 없으므로, 최소 분배 시간은 적어도 F/dminF/d_{min} 이다.
  • 시스템의 전체 업로드 용량은 전체적으로 서버의 업로드 속도와 각 피어들의 업로드 속도를 더한 것이다. 즉, utotal=us+u1+...+uNu_{total} = u_{s}+ u_{1}+ ... + u_N 이다. 시스템은 N개 피어들 각각에게 F 비트를 전달해야 한다. 이는 utotalu_{total} 보다 더 빠르게 할 수 없으므로, 최소 분배 시간은 적어도 NF/(us+u1+...+uN)NF/(u_{s}+ u_{1}+ ... + u_N) 이다.

이를 결합하면 P2P에 대한 최소 분배 시간 DP2PD_{P2P} 는 다음과 같다.
DP2Pmax{Fus,Fdmin,NFus+i=1Nui}D_{P2P} \ge max \{ \frac{F}{u_{s}}, \frac{F}{d_{min}}, \frac{NF}{u_{s}+ \sum\limits_{i=1}^Nu_i} \}

클라이언트-서버의 경우 피어의 수가 증가함에 따라 최소 분배 시간이 선형적으로, 한계없이 증가하지만 P2P 구조의 경우 최소 분배 시간이 클라이언트-서버 구조의 분배 시간보다 항상 작지는 않다. 따라서 P2P 구조를 가진 애플리케이션은 자가 확장성을 갖는다.

비트토렌트

비트토렌트 용어로 특정 파일의 분배에 참여하는 모든 피어의 모임을 토렌트라고 부른다. 토렌트에 참여하는 피어들은 서로에게서 같은 크기의 청크를 다운로드한다.
피어가 청크를 로드할 때 피어는 또한 청크를 다른 피어들에게 업로드한다.

비트토렌트는 트래커라는 인프라스트럭처 노드를 갖고 있다. 한 피어가 토렌트에 가입할 때 트래커에 자신을 등록하고 주기적으로 자신이 아직 토렌트에 있음을 알린다. 이러한 방식으로 트래커가 토렌트에 참여하는 피어들을 추적할 수 있다.

새로운 피어 A가 토렌트에 가입할 때 트래커는 참여하고 있는 피어 집합에서 임의로 피어들의 부분집합을 선택하여 해당 피어들의 IP 주소를 A에게 보낸다. A는 이 목록에 있는 모든 피어와 동시에 TCP 연결을 설정하고, 이 피어들을 ‘이웃 피어’ 라고 하자.
시간이 지남에 따라 피어들 중 일부는 떠나고 다른 피어들이 A와 TCP 연결을 시도하는 등 시간에 따라 변동될 수 있다. 주기적으로 A는 이웃 피어들 각각에게 그들이 갖고 있는 청크 목록을 요구한다.

A는 이웃으로부터 어떤 청크를 먼저 요구할까? 이때 가장 드문 것 먼저 (rarest first) 라는 기술을 사용한다. A가 갖고 있지 않은 청크 중에서 이웃 가운데 가장 드문 청크를 결정하고 요구하는 것이다.
어느 요청에 A가 응답할지를 결정하기 위해 비트토렌트는 현명한 교역(trade) 알고리즘을 사용한다. A가 가장 빠른 속도로 A에게 데이터를 제공하는 이웃에게 우선순위를 주는 것이다. 특히 A의 각 이웃에 대해 A는 계속해서 A가 비트를 수신하는 속도를 측정하고 가장 빠르게 전송하는 4개의 피어를 결정한다. 그러고 나서 A는 이 4개의 피어에게 청크를 보냄으로써 보답한다. A는 10초마다 속도를 재계산하고 4개의 피어 집합을 수정한다. 비트토렌트 용어로 이러한 4개의 피어를 활성화되었다고 한다.

또한 A는 30초마다 임의로 피어 하나를 추가로 선택하여 청크를 보낸다. 임의로 선택된 피어를 B라고 하자. 비트토렌트 용어로 B는 낙관적으로 활성화되었다고 한다. A가 B에게 데이터를 보내고 있기 때문에 A는 B의 4개 업로더 중 하나가 될 수 있다.
30초마다 A는 임의로 새로운 교역 파트너를 선택하고 그 파트너와 교역을 시작한다. 두 피어들이 교역에 만족하면 그들은 서로를 4개의 목록에 넣을 것이고 피어 중 누구 하나가 더 좋은 파트너를 만날 때까지 서로와 교역을 계속할 것이다.
또한 임의의 이웃 선택은 새로운 피어들이 청크를 얻게 하여 그들이 교역할 수 있는 무엇인가를 가질 수 있다. 이러한 5개 피어 외의 모든 이웃 피어는 비활성화되어 있다.

기술한 교역을 위한 보상 방식을 TFT(tit-for-tat) 라고 한다. 이 보상 방식은 회피할 수 있지만, 비트토렌트 생태계는 매우 성공적이며, 수십만 개의 토렌트에서 동시에 수백만의 피어들이 능동적으로 파일을 공유하고 있다.

비디오 스트리밍과 콘텐츠 분배 네트워크

인터넷 비디오

스트리밍 비디오 애플리케이션에서 녹화된 비디오는 서버에 저장되어 사용자가 비디오 시청을 서버에게 온디맨드로 요청한다.

비디오는 이미지의 연속으로서 일반적으로 초당 24개 또는 30개의 이미지로 일정한 속도로 표시된다. 압축되지 않은 디지털 인코딩된 이미지는 픽셀 단위로 구성되며, 각 픽셀은 휘도와 색상을 나타내는 여러 비트들로 인코딩된다.
비디오의 중요한 특징은 압축될 수 있다는 것인데, 비디오 품질과 비트 전송률은 서로 반비례한다.

네트워킹 측면에서 비디오의 가장 두드러진 특성은 높은 비트 전송률이다. 압축된 인터넷 비디오는 일반적으로 고화질 동영상을 스트리밍하기 위해 100 kbps 에서 4 Mbps 이상으로 구성된다.

지금까지 스트리밍 비디오에서 가장 중요한 성능 척도는 평균 종단 간 처리량이다. 연속재생을 제공하기 위해, 네트워크는 압축된 비디오의 전송률 이상의 스트리밍 애플리케이션에 대한 평균 처리량을 제공해야 한다.

또한 압축을 사용하여 동일한 비디오를 여러 버전의 품질로 만들 수 있다. 사용자는 현재 사용 가능한 대역폭을 선택하여 보고 싶은 버전을 결정할 수 있다.

HTTP 스트리밍 및 DASH

인터넷 비디오 회사에서 스트리밍 서비스를 제공하는 가장 단순한 방법은 단일한 거대 데이터 센터를 구축하고 모든 비디오 자료를 데이터 센터에 저장한 뒤 전 세계의 사용자에게 비디오 스트림을 데이터 센터로부터 직접 전송하는 것이다.

그러나 이 방법은 중대한 문제점들이 있다.

  1. 클라이언트가 데이터 센터로부터 지역적으로 먼 지점에 있는 경우, 서버로부터 클라이언트의 패킷 경로는 많은 다양한 통신 링크와 ISP 를 거쳐가게 되는데, 이 링크들 중 하나라도 비디오 소비율보다 낮은 전송용량을 갖는다면 종단 간 처리율이 낮아진다. 종단 간 경로 길이가 길어질수록 이런 현상은 증가한다.
  2. 인기 있는 비디오는 같은 통신 링크를 통해 여러 번 반복적으로 전송된다. 이는 네트워크 대역폭의 낭비는 물론이고 인터넷 비디오 회사가 회선을 제공하는 ISP 들에게 동일한 바이트를 전송하는 것에 대해 중복 비용을 지불해야 한다.
  3. 단일한 데이터 센터를 구축하면 한 번의 장애로 인해 전체 서비스가 중단될 수 있는 위험이 있다.

거의 대부분의 비디오 스트리밍 회사들은 콘텐츠 분배 네트워크 (Content Distribution Network, CDN) 를 이용한다. CDN 은 다수의 지점에 분산된 서버들을 운영하며, 비디오 및 다른 형태의 웹 콘텐츠 데이터의 복사본을 이러한 분산 서버에 저장한다. 사용자는 최선의 서비스와 사용자 경험을 제공할 수 있는 지점의 CDN 서버로 연결된다.

CDN은 콘텐츠 제공자가 소유한 사설 CDN 일 수 있으며, 또는 제3자가 운영하는 CDN 을 통해 다수의 콘텐츠 제공자가 서비스할 수도 있다.

CDN은 일반적으로 서버의 위치에 대해 두 가지 철학 중 하나를 채용하고 있다.

  • Enter Deep: 서버 클러스터를 세계 곳곳의 접속 네트워크에 구축함으로써 ISP 의 접속 네트워크로 깊숙이 들어가는 것이다. 서버를 최대한 사용자 가까이에 위치시켜 사용자와 CDN 서버 사이의 링크 및 라우터 수를 줄이고 사용자가 경험하는 지연 시간 및 처리율을 개선한다. 그러나 고도로 분산된 설계로 인해 서버 클러스터를 유지 관리하는 비용이 커진다.
  • Bring Home: 좀 더 적은 수의 핵심 지점에 큰 규모의 서버 클러스터를 구축하여 ISP 를 Home 으로 가져오는 개념이다. 접속 ISP 에 연결하는 대신, 이러한 CDN 들은 일반적으로 그들의 클러스터를 인터넷 교환 지점 (Internet Exchange Point, IXP) 에 배치된다. 클러스터 유지 및 관리 비용이 줄어드는 대신에 사용자가 느끼는 지연 시간과 처리율은 상대적으로 나빠진다.

서버 클러스터의 위치가 정해지면 CDN 은 콘텐츠의 복사본을 클러스터에 저장한다. CDN 은 클러스터에 대해 푸시 방식이 아닌 풀 방식을 사용한다. 어떤 사용자가 지역 클러스터에 없는 비디오를 요청하면, 해당 비디오를 중앙 서버나 다른 클러스터로부터 전송받아 사용자에게 서비스하는 동시에 복사본을 만들어 저장한다. 인터넷 캐시와 마찬가지로 클러스터의 저장 공간이 가득 차면 자주 사용되지 않는 비디오 데이터는 삭제된다.

CDN 동작

사용자의 호스트가 웹 브라우저가 URL 을 지정함으로써 특정 비디오의 재생을 요청하면 CDN은 그 요청을 가로채서 (1) 그 시점에서 클라이언트에게 가장 적당한 CDN 클러스터를 선택하고, (2) 클라이언트의 요청을 해당 클러스터의 서버로 연결한다.

대부분의 CDN 은 사용자의 요청을 가로채고 다른 곳으로 연결하는 데 DNS 를 사용한다.

  1. 사용자가 NetCinema 의 웹 페이지를 방문한다.
  2. 사용자가 http://video.netcinema.com/6Y34kJ 링크를 클릭하면 사용자의 호스트는 video.netcinema.com 에 대한 DNS 질의를 보낸다.
  3. 사용자의 지역 DNS 서버 (LDNS) 는 호스트 이름의 video 를 감지하고 해당 질의를 NetCinema 의 책임 DNS 서버로 전달한다. NetCinema 책임 DNS 서버는 해당 질의를 KingCDN으로 연결하기 위해 IP 주소 대신에 KingCDN의 호스트 이름을 LDNS 에게 알려준다.
  4. 이 시점부터 DNS 질의는 KingCDN의 사설 DNS 구조로 들어가게 된다. 사용자의 LDNS는 a1105.kingcdn.com 에 대한 두 번째 질의를 보내고 이는 KingCDN의 DNS에 의해 KingCDN 콘텐츠 서버의 IP 주소로 변환되어 LDNS 에게 응답된다. 이때 클라이언트가 콘텐츠를 전송받게 될 서버가 결정된다.
  5. LDNS는 콘텐츠를 제공할 CDN 서버의 IP 주소를 사용자 호스트에게 알려준다.
  6. 클라이언트는 KingCDN 서버의 IP 주소를 얻고 나면, 해당 IP 주소로 직접 TCP 연결을 설정하고 비디오에 대한 HTTP GET 요청을 전송한다. 만약 DASH 가 사용된다면 서버는 먼저 각기 다른 버전의 비디오에 대한 URL 목록을 포함하는 매니페스트 파일을 클라이언트에게 전송하고 클라이언트는 동적으로 각기 다른 버전의 비디오 조각 단위 데이터를 선택할 수 있다.

클러스터 선택 정책

CDN 구축의 핵심 중 하나는 클러스터 선택 정책이다. 이는 클라이언트를 동적으로 어떤 서버 클러스터 또는 CDN 데이터 센터로 연결하는 방식이다.

IP 주소를 알아낸 CDN 은 해당 IP 주소에 기초해 최선의 클러스터를 선택할 필요가 있다. 일반적으로 CDN 은 각기 고유한 클러스터 선택 정책을 사용한다.

간단한 클러스터 정책의 하나로 클라이언트에게 지리적으로 가장 가까운 클러스터를 할당하는 기법이 있다. 상용 지리정보 데이터베이스를 이용하면 LDNS 의 IP 주소는 지리적으로 매핑될 수 있다. DNS 질의가 특정 LDNS 로부터 도착하면 CDN은 해당 LDNS에서 가장 가까운 클러스터를 선택한다.

일부 클라이언트에서는 위와 같은 방식이 잘 동작하지 않는데, 그 이유는 지리적으로는 가장 가까운 클러스터가 네트워크 경로의 길이 홉의 수에 따라 가장 가까운 클러스터가 아닐 수 있기 때문이다.
또한 DNS 기반 방법에 내재된 문제로서, 일부 사용자는 상당히 멀리 있는 DNS 서버를 LDNS로 사용하도록 설정할 수 있다. 이 경우 LDNS IP 주소를 기반으로 선택한 클러스터는 사용자 호스트로부터 멀리 위치하게 된다. 또한 이 방법은 인터넷 경로의 지연이나 가용 대역폭의 변화 등은 무시하고 항상 같은 클러스터를 클라이언트에게 할당하게 된다.

현재의 네트워크 트래픽 상황을 반영한 최선의 클러스터를 선택하기 위해 CDN 은 주기적으로 클러스터와 클라이언트 간의 지연 및 손실 성능에 대한 실시간 측정을 수행하기도 한다.

소켓 프로그래밍: 네트워크 애플리케이션 생성

일반적인 네트워크 애플리케이션은 2개의 종단 시스템에 존재하는 클라이언트 프로그램과 서버 프로그램으로 구성된다. 이러한 두 프로그램을 수행하면 클라이언트와 서버 프로세스가 생성되고, 두 프로세스가 소켓으로부터 읽고, 소켓에 쓰기를 통해 서로 통신한다. 네트워크 애플리케이션을 생성할 때 개발자의 주 업무는 클라이언트와 서버 프로그램 모두에 대한 코드를 작성하는 것이다.

클라이언트-서버 애플리케이션에는 두 가지 형태가 있다. 한 형태는 RFC에 정의된 표준 프로토콜을 구현하는 클라이언트-서버 애플리케이션이다. 이러한 애플리케이션은 개방형으로 불린다. 그 동작을 규정하는 규칙들이 모두에게 알려져 있다. 그 경우 클라이언트와 서버 프로그램은 RFC에 정의된 규칙을 따라야 한다. 마찬가지로 서버 프로그램도 HTTP 서버 프로토콜을 구현할 수 있다.

오늘날 대부분의 네트워크 애플리케이션은 독립 개발자가 개발한 클라이언트와 서버 프로그램 간의 통신을 포함한다.

다른 형태의 네트워크 애플리케이션은 개인의 독점적인 네트워크 애플리케이션이다. 이 경우 클라이언트와 서버 프로그램은 RFC 또는 다른 곳에 공식적으로 출판되지 않은 애플리케이션 계층 프로토콜을 채택한다. 개인 개발자는 클라이언트와 서버 프로그램을 모두 생성하고, 이 개발자는 코드에 무엇을 사용할지를 완전히 제어한다. 그러나 그 코드는 공개된 프로토콜로 구현되지 않기 때문에, 다른 독립 개발자는 이 애플리케이션과 상호작용하는 코드를 개발할 수 없다.

개발 단계 동안 개발자가 우선해야 할 결정 중의 하나는 그 애플리케이션이 TCP 를 이용하는지, UDP 를 이용하는지에 대한 것이다. TCP 는 연결지향형 서비스이고 신뢰적 바이트 스트림 채널을 제공하는데, 이 채널을 통해 데이터가 두 종단 시스템 사이를 흐르게 된다. UDP 는 비연결형이고 한 종단 시스템에서 다른 곳으로 데이터를 독립적인 패킷으로 만들어서 보내는데, 전송에 대한 보장은 하지 않는다.
클라이언트 또는 서버 프로그램이 RFC에 정의된 프로토콜을 구현할 때, 그 프로토콜과 연관된 잘 알려진 포트 번호를 사용해야 한다. 역으로, 독점적인 애플리케이션을 개발할 때 개발자는 잘 알려진 포트 번호를 사용하지 않도록 유의해야 한다.

UDP 를 이용한 소켓 프로그래밍

다른 컴퓨터에서 수행되는 프로세스 간의 통신은 소켓에 메시지를 보냄으로써 실행한다. 애플리케이션 개발자는 소켓의 애플리케이션 계층에 대한 제어권을 갖지만 트랜스포트 계층 쪽에 대한 제어권은 거의 없다.

송신 프로세스가 데이터의 패킷을 소켓 문밖으로 밀어내기 전에, UDP를 사용할 때 먼저 패킷에 목적지 주소를 붙여넣어야 한다. 이 패킷이 송신자의 소켓을 통과한 후 인터넷은 이 목적지 주소를 이용하여 그 패킷을 인터넷을 통해 수신 프로세스에 있는 소켓으로 라우트할 것이다. 패킷이 수신 소켓에 도착하면 수신 프로세스는 소켓을 통해 그 패킷을 추출하고 다음에 패킷의 콘텐츠를 조사하고 적절한 동작을 취한다.

패킷에 붙여지는 목적지 주소는 그 목적지 호스트의 IP 주소가 목적지 주소의 일부가 된다. 패킷에 목적지 주소를 포함함으로써 인터넷의 라우터는 목적지 호스트로 인터넷을 통해 패킷을 라우트할 수 있다. 그러나 호스트는 하나 혹은 그 이상의 소켓을 갖는 많은 네트워크 애플리케이션 프로세스를 수행하고 있을 수 있기 때문에 목적지 호스트 내의 특정한 소켓을 식별할 필요가 있다. 소켓이 생성될 때 포트 번호라고 하는 식별자가 소켓에 할당된다. 즉, 패킷의 목적지 주소는 소켓의 포트 번호도 포함한다.

송신 프로세스는 목적지 호스트의 IP 주소와 목적지 소켓의 포트 번호로 구성된 목적지 주소를 패킷에 붙인다. 더 나아가, 송신자의 출발지 주소도 패킷에 붙여짐을 볼 수 있다. 그러나 출발지 주소를 패킷에 붙이는 것은 일반적으로 UDP 애플리케이션 코드가 아닌 하부 운영체제가 자동으로 실행한다.

TCP 소켓 프로그래밍

TCP는 연결지향 프로토콜로, 클라이언트와 서버가 서로에게 데이터를 보내기 전에 먼저 TCP 연결을 설정할 필요가 있음을 의미한다. TCP 연결의 한쪽은 클라이언트 소켓에 연결되고 다른 쪽은 서버 소켓에 연결된다. TCP 연결을 생성할 때 클라이언트 소켓 주소와 서버 소켓 주소를 연결과 연관시킨다. TCP 연결이 설정된 후 한쪽에서 다른 쪽으로 데이터를 보내려면 소켓을 통해 데이터를 TCP 연결로 보내면 된다.

클라이언트는 서버로의 접속을 먼저 시도한다. 서버는 클라이언트의 초기 접속에 응대할 수 있도록 준비하고 있어야 하는데, 여기에는 두 가지 의미가 있다.

  1. UDP에서와 마찬가지로 TCP 서버는 클라이언트가 접속을 시도하기 전에 프로세스를 먼저 수행하고 있어야 한다.
  2. 서버 프로그램은 임의의 컴퓨터에서 수행되고 있는 클라이언트로부터의 초기 접속을 처리하는 특별한 출입문을 가져야 한다.

서버 프로세스가 수행되면 클라이언트 프로세스는 서버로의 TCP 연결을 시도한다. 이는 클라이언트 프로그램에서 TCP 소켓을 생성함으로써 가능하다. 클라이언트는 TCP 소켓을 생성할 때 서버의 IP 주소와 소켓의 포트 번호를 명시한다. 소켓을 생성한 후 클라이언트는 세 방향 핸드셰이크를 하고 서버와 TCP 연결을 설정한다. 트랜스포트 계층에서 일어나는 세 방향 핸드셰이크를 클라이언트와 서버 프로그램은 전혀 인식하지 못한다.

애플리케이션 관점에서 볼 때 클라이언트의 소켓과 서버의 연결 소켓은 파이프에 의해 직접 연결된다. 클라이언트 프로세스는 자신의 소켓으로 임의의 바이트를 보낼 수 있으며 보낸 순서대로 서버 프로세스가 바이트를 수신하도록 TCP가 보장한다 .따라서 TCP는 클라이언트와 서버 프로세스간에 신뢰적 서비스를 제공한다. 또한 클라이언트 프로세스는 소켓으로 바이트를 보낼 수 있을 뿐만 아니라 소켓으로부터 바이트를 수신할 수 있다. 마찬가지로 서버 프로세스도 연결 소켓으로부터 바이트를 수신할 수 있을 뿐만 아니라 연결 소켓으로 바이트를 보낼 수 있다.